<template>
    <div
        class="flow-designer"
        ref="flowContainer"
        @contextmenu.prevent="showContextMenu($event)"
        @click="hideContextMenu()"
    >
        <!-- 节点列表 -->
        <div
            v-for="node in nodes"
            :key="node.id"
            class="flow-node"
            :class="[
                `node-type-${node.type}`,
                { 'node-selected': selectedNode === node.id },
            ]"
            :style="{ left: node.x + 'px', top: node.y + 'px' }"
            @mousedown="selectNode(node.id, $event)"
            @contextmenu.prevent="showNodeMenu(node.id, $event)"
        >
            <div class="node-header">
                <span class="node-icon">{{ getNodeIcon(node.type) }}</span>
                <input
                    v-if="editingNode === node.id"
                    v-model="node.title"
                    class="node-title-input"
                    @blur="saveNodeTitle(node)"
                    @keyup.enter="saveNodeTitle(node)"
                    @click.stop
                    ref="titleInput"
                />
                <span v-else @dblclick="editNodeTitle(node.id)">{{
                    node.title
                }}</span>
                <span class="node-close" @click.stop="deleteNode(node.id)"
                    >×</span
                >
            </div>
            <div class="node-content">
                <textarea
                    v-if="editingContent === node.id"
                    v-model="node.content"
                    class="node-content-input"
                    @blur="saveNodeContent(node)"
                    @click.stop
                    ref="contentInput"
                ></textarea>
                <div v-else @dblclick="editNodeContent(node.id)">
                    {{ node.content }}
                </div>
            </div>
            <div
                class="node-handle node-input"
                @mousedown.stop="startConnection($event, null, node.id)"
                title="连接输入"
            ></div>
            <div
                class="node-handle node-output"
                @mousedown.stop="startConnection($event, node.id, null)"
                title="连接输出"
            ></div>
        </div>

        <!-- 连接线 -->
        <svg class="flow-connectors">
            <path
                v-for="(conn, index) in connections"
                :key="index"
                :d="conn.path"
                stroke="#999"
                stroke-width="2"
                fill="none"
                marker-end="url(#arrowhead)"
            />

            <!-- 临时连接线 -->
            <path
                v-if="tempConnection"
                :d="tempConnection.path"
                stroke="#4CAF50"
                stroke-width="2"
                fill="none"
                stroke-dasharray="5,5"
            />

            <defs>
                <marker
                    id="arrowhead"
                    markerWidth="10"
                    markerHeight="7"
                    refX="9"
                    refY="3.5"
                    orient="auto"
                >
                    <polygon points="0 0, 10 3.5, 0 7" fill="#999" />
                </marker>
            </defs>
        </svg>

        <!-- 右键菜单 -->
        <div
            v-if="contextMenu.visible"
            class="context-menu"
            :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }"
        >
            <div
                v-for="item in contextMenu.items"
                :key="item.label"
                class="menu-item"
                @click="handleMenuClick(item)"
            >
                {{ item.label }}
            </div>
        </div>

        <!-- 节点属性编辑器 -->
        <div
            v-if="nodeEditor.visible"
            class="node-editor"
            :style="{ left: nodeEditor.x + 'px', top: nodeEditor.y + 'px' }"
        >
            <div class="editor-header">节点属性</div>
            <div class="editor-body">
                <div class="form-group">
                    <label>节点标题</label>
                    <input v-model="nodeEditor.title" class="form-control" />
                </div>
                <div class="form-group">
                    <label>节点内容</label>
                    <textarea
                        v-model="nodeEditor.content"
                        class="form-control"
                    ></textarea>
                </div>
                <div class="form-group">
                    <label>节点类型</label>
                    <select v-model="nodeEditor.type" class="form-control">
                        <option value="start">开始节点</option>
                        <option value="process">处理节点</option>
                        <option value="decision">决策节点</option>
                        <option value="end">结束节点</option>
                    </select>
                </div>
                <div class="editor-actions">
                    <button @click="saveNodeEditor" class="btn btn-primary">
                        保存
                    </button>
                    <button @click="closeNodeEditor" class="btn btn-default">
                        取消
                    </button>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
let nodeIdCounter = 1;
let connIdCounter = 1;

export default {
    data() {
        return {
            nodes: [
                {
                    id: nodeIdCounter++,
                    title: "开始节点",
                    content: "流程开始",
                    type: "start",
                    x: 100,
                    y: 100,
                },
                {
                    id: nodeIdCounter++,
                    title: "处理节点",
                    content: "数据处理",
                    type: "process",
                    x: 300,
                    y: 200,
                },
                {
                    id: nodeIdCounter++,
                    title: "结束节点",
                    content: "流程结束",
                    type: "end",
                    x: 500,
                    y: 100,
                },
            ],
            connections: [],
            selectedNode: null,
            draggingNode: null,
            startPos: { x: 0, y: 0 },
            tempConnection: null,
            editingNode: null,
            editingContent: null,
            contextMenu: {
                visible: false,
                x: 0,
                y: 0,
                items: [
                    { label: "添加开始节点", type: "start" },
                    { label: "添加处理节点", type: "process" },
                    { label: "添加结束节点", type: "end" },
                    { label: "添加决策节点", type: "decision" },
                ],
            },
            nodeEditor: {
                visible: false,
                x: 0,
                y: 0,
                nodeId: null,
                title: "",
                content: "",
                type: "process",
            },
            containerRect: null,
        };
    },
    methods: {
        // 获取节点图标
        getNodeIcon(type) {
            const icons = {
                start: "▶",
                process: "⚙",
                decision: "↻",
                end: "■",
            };
            return icons[type] || "○";
        },

        // 选择节点
        selectNode(nodeId, event) {
            this.selectedNode = nodeId;

            if (event.button === 0) {
                // 左键
                const node = this.nodes.find((n) => n.id === nodeId);
                if (node) {
                    this.draggingNode = node;
                    this.startPos = {
                        x: event.clientX - node.x,
                        y: event.clientY - node.y,
                    };
                }
            }
        },

        // 开始创建连接
        startConnection(event, fromId, toId) {
            event.stopPropagation();

            const node = this.nodes.find((n) => n.id === (fromId || toId));
            if (!node) return;

            this.updateContainerRect();

            const isOutput = !!fromId;
            // 精确计算手柄位置
            const handleX = node.x + (isOutput ? 200 : 0) + (isOutput ? 0 : 12);
            const handleY = node.y + 40;

            this.tempConnection = {
                from: fromId,
                to: toId,
                startX: handleX,
                startY: handleY,
                endX: event.clientX - this.containerRect.left,
                endY: event.clientY - this.containerRect.top,
                path: this.createPath(
                    handleX,
                    handleY,
                    event.clientX - this.containerRect.left,
                    event.clientY - this.containerRect.top
                ),
            };

            document.addEventListener("mousemove", this.updateTempConnection);
            document.addEventListener("mouseup", this.finalizeConnection);
        },

        // 更新临时连接线
        updateTempConnection(event) {
            if (!this.tempConnection) return;

            this.updateContainerRect();

            const mouseX = event.clientX - this.containerRect.left;
            const mouseY = event.clientY - this.containerRect.top;

            this.tempConnection.endX = mouseX;
            this.tempConnection.endY = mouseY;
            this.tempConnection.path = this.createPath(
                this.tempConnection.startX,
                this.tempConnection.startY,
                mouseX,
                mouseY
            );
        },

        // 完成连接创建
        finalizeConnection(event) {
            if (!this.tempConnection) return;

            document.removeEventListener(
                "mousemove",
                this.updateTempConnection
            );
            document.removeEventListener("mouseup", this.finalizeConnection);

            this.updateContainerRect();

            const mouseX = event.clientX - this.containerRect.left;
            const mouseY = event.clientY - this.containerRect.top;

            // 寻找目标节点
            const targetNode = this.nodes.find((node) => {
                const nodeRight = node.x + 200;
                const nodeBottom = node.y + 100;
                return (
                    mouseX >= node.x &&
                    mouseX <= nodeRight &&
                    mouseY >= node.y &&
                    mouseY <= nodeBottom
                );
            });

            if (targetNode) {
                const fromId = this.tempConnection.from || targetNode.id;
                const toId = this.tempConnection.to || targetNode.id;

                if (fromId !== toId) {
                    // 检查连接是否已存在
                    const exists = this.connections.some(
                        (conn) => conn.from === fromId && conn.to === toId
                    );

                    if (!exists) {
                        this.connections.push({
                            id: connIdCounter++,
                            from: fromId,
                            to: toId,
                        });
                        this.calculateConnections();
                    }
                }
            }

            this.tempConnection = null;
        },

        // 计算所有连接线路径
        calculateConnections() {
            this.connections = this.connections.map((conn) => {
                const fromNode = this.nodes.find((n) => n.id === conn.from);
                const toNode = this.nodes.find((n) => n.id === conn.to);

                if (!fromNode || !toNode) return conn;

                // 精确计算连接点位置
                const fromX = fromNode.x + 200; // 输出点在右侧
                const fromY = fromNode.y + 40; // 垂直居中
                const toX = toNode.x; // 输入点在左侧
                const toY = toNode.y + 40; // 垂直居中

                const path = this.createPath(fromX, fromY, toX, toY);

                return { ...conn, path };
            });
        },

        // 创建贝塞尔曲线路径
        createPath(fromX, fromY, toX, toY) {
            // 创建更平滑的贝塞尔曲线路径
            const ctrlX1 = fromX + Math.abs(toX - fromX) * 0.5;
            const ctrlX2 = toX - Math.abs(toX - fromX) * 0.5;
            return `M${fromX},${fromY} C${ctrlX1},${fromY} ${ctrlX2},${toY} ${toX},${toY}`;
        },

        // 显示右键菜单
        showContextMenu(event) {
            this.updateContainerRect();
            this.contextMenu = {
                visible: true,
                x: event.clientX,
                y: event.clientY,
                items: this.contextMenu.items,
            };
            this.hideNodeMenu();
        },

        // 显示节点右键菜单
        showNodeMenu(nodeId, event) {
            this.updateContainerRect();
            this.nodeEditor = {
                visible: true,
                x: event.clientX,
                y: event.clientY,
                nodeId,
                title: this.nodes.find((n) => n.id === nodeId).title,
                content: this.nodes.find((n) => n.id === nodeId).content,
                type: this.nodes.find((n) => n.id === nodeId).type,
            };
            this.hideContextMenu();
        },

        // 隐藏右键菜单
        hideContextMenu() {
            this.contextMenu.visible = false;
        },

        // 隐藏节点菜单
        hideNodeMenu() {
            this.nodeEditor.visible = false;
        },

        // 处理菜单点击
        handleMenuClick(item) {
            this.updateContainerRect();
            this.addNode(
                item.type,
                this.contextMenu.x - this.containerRect.left,
                this.contextMenu.y - this.containerRect.top
            );
            this.hideContextMenu();
        },

        // 添加新节点
        addNode(type, x, y) {
            const titles = {
                start: "开始节点",
                process: "处理节点",
                decision: "决策节点",
                end: "结束节点",
            };

            const contents = {
                start: "流程开始",
                process: "数据处理",
                decision: "条件判断",
                end: "流程结束",
            };

            this.nodes.push({
                id: nodeIdCounter++,
                title: titles[type] || "新节点",
                content: contents[type] || "节点内容",
                type,
                x: x - 100, // 居中定位
                y: y - 50, // 居中定位
            });
        },

        // 删除节点
        deleteNode(nodeId) {
            if (confirm("确定要删除这个节点吗？")) {
                this.nodes = this.nodes.filter((n) => n.id !== nodeId);
                this.connections = this.connections.filter(
                    (conn) => conn.from !== nodeId && conn.to !== nodeId
                );
                if (this.selectedNode === nodeId) {
                    this.selectedNode = null;
                }
            }
        },

        // 编辑节点标题
        editNodeTitle(nodeId) {
            this.editingNode = nodeId;
            this.$nextTick(() => {
                this.$refs.titleInput[
                    this.nodes.findIndex((n) => n.id === nodeId)
                ].focus();
            });
        },

        // 保存节点标题
        saveNodeTitle(node) {
            this.editingNode = null;
            // 这里可以添加保存到后端的逻辑
        },

        // 编辑节点内容
        editNodeContent(nodeId) {
            this.editingContent = nodeId;
            this.$nextTick(() => {
                this.$refs.contentInput[
                    this.nodes.findIndex((n) => n.id === nodeId)
                ].focus();
            });
        },

        // 保存节点内容
        saveNodeContent(node) {
            this.editingContent = null;
            // 这里可以添加保存到后端的逻辑
        },

        // 保存节点编辑器内容
        saveNodeEditor() {
            const node = this.nodes.find(
                (n) => n.id === this.nodeEditor.nodeId
            );
            if (node) {
                node.title = this.nodeEditor.title;
                node.content = this.nodeEditor.content;
                node.type = this.nodeEditor.type;
            }
            this.closeNodeEditor();
        },

        // 关闭节点编辑器
        closeNodeEditor() {
            this.nodeEditor.visible = false;
        },

        // 更新容器位置信息
        updateContainerRect() {
            if (this.$refs.flowContainer) {
                this.containerRect =
                    this.$refs.flowContainer.getBoundingClientRect();
            }
        },
    },
    mounted() {
        this.updateContainerRect();
        this.calculateConnections();

        const handleMouseMove = (event) => {
            if (this.draggingNode) {
                this.draggingNode.x = event.clientX - this.startPos.x;
                this.draggingNode.y = event.clientY - this.startPos.y;
                this.calculateConnections();
            }
        };

        const handleMouseUp = () => {
            this.draggingNode = null;
        };

        document.addEventListener("mousemove", handleMouseMove);
        document.addEventListener("mouseup", handleMouseUp);

        this.$once("hook:beforeDestroy", () => {
            document.removeEventListener("mousemove", handleMouseMove);
            document.removeEventListener("mouseup", handleMouseUp);
        });

        // 窗口大小变化时更新容器位置
        window.addEventListener("resize", this.updateContainerRect);
        this.$once("hook:beforeDestroy", () => {
            window.removeEventListener("resize", this.updateContainerRect);
        });
    },
};
</script>

<style>
.flow-designer {
    position: relative;
    width: 100%;
    height: 800px;
    border: 1px solid #eee;
    background-color: #f9f9f9;
    overflow: hidden;
}

.flow-node {
    position: absolute;
    width: 200px;
    min-height: 80px;
    border: 2px solid #ccc;
    border-radius: 6px;
    background: white;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    cursor: move;
    user-select: none;
}

.node-header {
    padding: 8px 12px;
    background: #f5f5f5;
    border-bottom: 1px solid #ddd;
    font-weight: bold;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.node-icon {
    margin-right: 8px;
    font-size: 14px;
}

.node-title-input {
    flex: 1;
    border: 1px solid #ddd;
    border-radius: 3px;
    padding: 2px 5px;
    margin: 0 5px;
}

.node-close {
    cursor: pointer;
    color: #999;
    font-size: 18px;
    line-height: 1;
    padding: 0 5px;
}

.node-close:hover {
    color: #f44336;
}

.node-content {
    padding: 12px;
    font-size: 13px;
    color: #666;
    min-height: 40px;
}

.node-content-input {
    width: 100%;
    height: 60px;
    border: 1px solid #ddd;
    border-radius: 3px;
    padding: 5px;
    resize: none;
}

.node-handle {
    position: absolute;
    width: 12px;
    height: 12px;
    border: 2px solid white;
    border-radius: 50%;
    cursor: crosshair;
    z-index: 10;
}

.node-input {
    left: -6px;
    top: 50%;
    transform: translateY(-50%);
    background: #2196f3;
}

.node-output {
    right: -6px;
    top: 50%;
    transform: translateY(-50%);
    background: #ff5722;
}

.flow-connectors {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

.context-menu,
.node-editor {
    position: fixed;
    background: white;
    border: 1px solid #ddd;
    border-radius: 4px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    z-index: 1000;
}

.node-editor {
    width: 250px;
}

.editor-header {
    padding: 8px 12px;
    background: #f5f5f5;
    border-bottom: 1px solid #ddd;
    font-weight: bold;
}

.editor-body {
    padding: 12px;
}

.form-group {
    margin-bottom: 10px;
}

.form-group label {
    display: block;
    margin-bottom: 5px;
    font-size: 12px;
    color: #666;
}

.form-control {
    width: 100%;
    padding: 5px;
    border: 1px solid #ddd;
    border-radius: 3px;
}

.editor-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 15px;
}

.btn {
    padding: 5px 10px;
    border-radius: 3px;
    cursor: pointer;
    margin-left: 5px;
}

.btn-primary {
    background: #2196f3;
    color: white;
    border: 1px solid #2196f3;
}

.btn-default {
    background: #f5f5f5;
    border: 1px solid #ddd;
}

.menu-item {
    padding: 8px 16px;
    cursor: pointer;
}

.menu-item:hover {
    background: #f5f5f5;
}

.node-type-start {
    border-color: #4caf50;
}

.node-type-start .node-header {
    background: #e8f5e9;
}

.node-type-process {
    border-color: #2196f3;
}

.node-type-process .node-header {
    background: #e3f2fd;
}

.node-type-decision {
    border-color: #ffc107;
}

.node-type-decision .node-header {
    background: #fff8e1;
}

.node-type-end {
    border-color: #f44336;
}

.node-type-end .node-header {
    background: #ffebee;
}

.node-selected {
    box-shadow: 0 0 0 2px #2196f3;
}
</style>
